/*-------------------------------------------------------------------------
 *
 * itemptr.c
 *	  POSTGRES 磁盘项目指针代码。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/backend/storage/page/itemptr.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "storage/itemptr.h"


/*
 * ItemPointerEquals
 *	如果两个项目指针指向同一项目，返回true，
 *	否则返回false。
 *
 * 注意：
 *	断言磁盘项目指针都是有效的！
 */
bool ItemPointerEquals(ItemPointer fc_pointer1, ItemPointer fc_pointer2)
{
	/*
	 * 我们确实希望ItemPointerData恰好是6个字节。
	 * 这个地方检查有点任意，但没有更好的地方。
	 */
	StaticAssertStmt(sizeof(ItemPointerData) == 3 * sizeof(uint16),
					 "ItemPointerData struct is improperly padded");

	if (ItemPointerGetBlockNumber(fc_pointer1) ==
		ItemPointerGetBlockNumber(fc_pointer2) &&
		ItemPointerGetOffsetNumber(fc_pointer1) ==
		ItemPointerGetOffsetNumber(fc_pointer2))
		return true;
	else
		return false;
}

/*
 * ItemPointerCompare
 *		用于项目指针的通用btree样式比较。
 */
int32 ItemPointerCompare(ItemPointer fc_arg1, ItemPointer fc_arg2)
{
	/*
	 * 使用ItemPointerGet{Offset,Block}NumberNoCheck来避免断言
	 * ip_posid != 0，这对用户提供的TID可能并不成立。
	 */
	BlockNumber fc_b1 = ItemPointerGetBlockNumberNoCheck(fc_arg1);
	BlockNumber fc_b2 = ItemPointerGetBlockNumberNoCheck(fc_arg2);

	if (fc_b1 < fc_b2)
		return -1;
	else if (fc_b1 > fc_b2)
		return 1;
	else if (ItemPointerGetOffsetNumberNoCheck(fc_arg1) <
			 ItemPointerGetOffsetNumberNoCheck(fc_arg2))
		return -1;
	else if (ItemPointerGetOffsetNumberNoCheck(fc_arg1) >
			 ItemPointerGetOffsetNumberNoCheck(fc_arg2))
		return 1;
	else
		return 0;
}

/*
 * ItemPointerInc
 *		将'pointer'增加1，仅关注ItemPointer类型范围限制，而不是
 *		MaxOffsetNumber和FirstOffsetNumber。
 *		这可能导致'pointer'变为!OffsetNumberIsValid。
 *
 * 如果指针已经是ItemPointer类型范围允许的最大值，则不执行任何操作。
 */
void ItemPointerInc(ItemPointer fc_pointer)
{
	BlockNumber fc_blk = ItemPointerGetBlockNumberNoCheck(fc_pointer);
	OffsetNumber fc_off = ItemPointerGetOffsetNumberNoCheck(fc_pointer);

	if (fc_off == PG_UINT16_MAX)
	{
		if (fc_blk != InvalidBlockNumber)
		{
			fc_off = 0;
			fc_blk++;
		}
	}
	else
		fc_off++;

	ItemPointerSet(fc_pointer, fc_blk, fc_off);
}

/*
 * ItemPointerDec
 *		将'pointer'减少1，仅关注ItemPointer类型范围限制，而不是
 *		MaxOffsetNumber和FirstOffsetNumber。
 *		这可能导致'pointer'变为!OffsetNumberIsValid。
 *
 * 如果指针已经是ItemPointer类型范围允许的最小值，则不执行任何操作。
 * 这依赖于FirstOffsetNumber为1而不是0。
 */
void ItemPointerDec(ItemPointer fc_pointer)
{
	BlockNumber fc_blk = ItemPointerGetBlockNumberNoCheck(fc_pointer);
	OffsetNumber fc_off = ItemPointerGetOffsetNumberNoCheck(fc_pointer);

	if (fc_off == 0)
	{
		if (fc_blk != 0)
		{
			fc_off = PG_UINT16_MAX;
			fc_blk--;
		}
	}
	else
		fc_off--;

	ItemPointerSet(fc_pointer, fc_blk, fc_off);
}
